related tdf#100074: prepare group shapes text input via writerfilter

Put various preps into place, that enable us to read txbxContent from
group shape children via the writerfilter parser, which gets us much
more features

Also:
- store shapecontexthandler on wrapper class in writerfilter
- move adding children shapes to ctor, not dtor
- remove RuntimeException in Writer's XShapes::add(), aligns this
  with Draw/Impress API semantics, and helps here when trying to
  add the same shape a 2nd time (which we then simply ignore)
- make oox's Shape notion of 'inside group' less ad-hoc
- make SwTextBoxHelper::getTextRectangle() cope with more than
  CustomShape - so passing in a group shape will also yield some
  sensible bounding box
- have SwTextBoxHelper handle group content, too
- derive WpsContext from ShapeContext, so we can later substitute it
  for that inside WpgContext
- keep WpgContext::onCreateContext() _for the moment_ with the old
  delegation to ShapeContext (needs to use WpsContext to enable
  writerfilter text input)

Change-Id: I2b0f0583e21137f3321a8dc13823058b14d19773
Reviewed-on: https://gerrit.libreoffice.org/65914
Tested-by: Jenkins
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
diff --git a/include/oox/drawingml/shape.hxx b/include/oox/drawingml/shape.hxx
index 646fe01..2197266 100644
--- a/include/oox/drawingml/shape.hxx
+++ b/include/oox/drawingml/shape.hxx
@@ -179,7 +179,8 @@
                            const css::uno::Reference< css::drawing::XShapes >& rxShapes,
                            const basegfx::B2DHomMatrix& aTransformation,
                            FillProperties& rShapeOrParentShapeFillProps,
                            ShapeIdMap* pShapeMap = nullptr );
                            ShapeIdMap* pShapeMap = nullptr,
                            bool bInGroup = false);

    const css::uno::Reference< css::drawing::XShape > &
                        getXShape() const { return mxShape; }
@@ -225,7 +226,8 @@
                            bool bClearText,
                            bool bDoNotInsertEmptyTextBody,
                            basegfx::B2DHomMatrix& aTransformation,
                            FillProperties& rShapeOrParentShapeFillProps
                            FillProperties& rShapeOrParentShapeFillProps,
                            bool bInGroup = false
                             );

    void                addChildren(
diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx
index 45d7946..8449082b 100644
--- a/oox/source/drawingml/shape.cxx
+++ b/oox/source/drawingml/shape.cxx
@@ -256,7 +256,8 @@
        const Reference< XShapes >& rxShapes,
        const basegfx::B2DHomMatrix& aTransformation,
        FillProperties& rShapeOrParentShapeFillProps,
        ShapeIdMap* pShapeMap )
        ShapeIdMap* pShapeMap,
        bool bInGroup )
{
    SAL_INFO("oox.drawingml", "Shape::addShape: id='" << msId << "'");

@@ -266,7 +267,7 @@
        if( !sServiceName.isEmpty() )
        {
            basegfx::B2DHomMatrix aMatrix( aTransformation );
            Reference< XShape > xShape( createAndInsert( rFilterBase, sServiceName, pTheme, rxShapes, false, false, aMatrix, rShapeOrParentShapeFillProps ) );
            Reference< XShape > xShape( createAndInsert( rFilterBase, sServiceName, pTheme, rxShapes, false, false, aMatrix, rShapeOrParentShapeFillProps, bInGroup ) );

            if( pShapeMap && !msId.isEmpty() )
            {
@@ -391,7 +392,7 @@
    for (auto const& child : rMaster.maChildren)
    {
        child->setMasterTextListStyle( mpMasterTextListStyle );
        child->addShape( rFilterBase, pTheme, rxShapes, aChildTransformation, getFillProperties(), pShapeMap );
        child->addShape( rFilterBase, pTheme, rxShapes, aChildTransformation, getFillProperties(), pShapeMap, true );
    }
}

@@ -586,7 +587,8 @@
        bool bClearText,
        bool bDoNotInsertEmptyTextBody,
        basegfx::B2DHomMatrix& aParentTransformation,
        FillProperties& rShapeOrParentShapeFillProps )
        FillProperties& rShapeOrParentShapeFillProps,
        bool bInGroup )
{
    bool bIsEmbMedia = false;
    SAL_INFO("oox.drawingml", "Shape::createAndInsert: id='" << msId << "' service='" << rServiceName << "'");
@@ -672,8 +674,8 @@
            maSize.Height ? maSize.Height : 1.0 );
    }

    bool bInGroup = !aParentTransformation.isIdentity();
    if( mbFlipH || mbFlipV || mnRotation != 0 || bInGroup )
    bool bNoTranslation = !aParentTransformation.isIdentity();
    if( mbFlipH || mbFlipV || mnRotation != 0 || bNoTranslation )
    {
        // calculate object's center
        basegfx::B2DPoint aCenter(0.5, 0.5);
@@ -768,7 +770,7 @@
            // tdf#106792 Not needed anymore due to the change in SdrPathObj::NbcResize:
            // tdf#96674: Guard against zero width or height.

            if (bIsWriter && bInGroup)
            if (bIsWriter && bNoTranslation)
                // Writer's draw page is in twips, and these points get passed
                // to core without any unit conversion when Writer
                // postprocesses only the group shape itself.
diff --git a/oox/source/drawingml/shapecontext.cxx b/oox/source/drawingml/shapecontext.cxx
index decf063..eae01bf 100644
--- a/oox/source/drawingml/shapecontext.cxx
+++ b/oox/source/drawingml/shapecontext.cxx
@@ -54,12 +54,12 @@
, mpMasterShapePtr( pMasterShapePtr )
, mpShapePtr( pShapePtr )
{
    if( mpMasterShapePtr.get() && mpShapePtr.get() )
        mpMasterShapePtr->addChild( mpShapePtr );
}

ShapeContext::~ShapeContext()
{
    if ( mpMasterShapePtr.get() && mpShapePtr.get() )
        mpMasterShapePtr->addChild( mpShapePtr );
}

ContextHandlerRef ShapeContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
diff --git a/oox/source/drawingml/shapegroupcontext.cxx b/oox/source/drawingml/shapegroupcontext.cxx
index 695cce7..c916642 100644
--- a/oox/source/drawingml/shapegroupcontext.cxx
+++ b/oox/source/drawingml/shapegroupcontext.cxx
@@ -51,12 +51,12 @@
{
    if( pMasterShapePtr )
        mpGroupShapePtr->setWps(pMasterShapePtr->getWps());
    if( mpMasterShapePtr.get() && mpGroupShapePtr.get() )
        mpMasterShapePtr->addChild( mpGroupShapePtr );
}

ShapeGroupContext::~ShapeGroupContext()
{
    if ( mpMasterShapePtr.get() && mpGroupShapePtr.get() )
        mpMasterShapePtr->addChild( mpGroupShapePtr );
}

ContextHandlerRef ShapeGroupContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
diff --git a/oox/source/shape/ShapeContextHandler.cxx b/oox/source/shape/ShapeContextHandler.cxx
index b80af12..2d2894e 100644
--- a/oox/source/shape/ShapeContextHandler.cxx
+++ b/oox/source/shape/ShapeContextHandler.cxx
@@ -119,7 +119,13 @@
        switch (getBaseToken(nStartElement))
        {
            case XML_wsp:
                mxWpsContext.set(new WpsContext(*rFragmentHandler, xShape));
                mxWpsContext.set(new WpsContext(
                                     *rFragmentHandler,
                                     xShape,
                                     pMasterShape,
                                     ShapePtr(
                                         new oox::drawingml::Shape(
                                             "com.sun.star.drawing.CustomShape"))));
                break;
            default:
                break;
@@ -500,7 +506,7 @@
                pShape->setPosition(maPosition);
                pShape->addShape(*mxFilterBase, mpThemePtr.get(), xShapes, aMatrix, pShape->getFillProperties());
                xResult = pShape->getXShape();
                mxWpgContext.clear();
                mxSavedShape = xResult;
            }
        }
        else if (mpShape.get() != nullptr)
diff --git a/oox/source/shape/WpgContext.cxx b/oox/source/shape/WpgContext.cxx
index 95264e5..c297ff16d 100644
--- a/oox/source/shape/WpgContext.cxx
+++ b/oox/source/shape/WpgContext.cxx
@@ -9,7 +9,9 @@


#include "WpgContext.hxx"
#include "WpsContext.hxx"
#include <sal/log.hxx>
#include <com/sun/star/drawing/XShape.hpp>
#include <drawingml/shapepropertiescontext.hxx>
#include <oox/drawingml/shapegroupcontext.hxx>
#include <oox/drawingml/graphicshapecontext.hxx>
@@ -49,6 +51,8 @@
        // it.
        oox::drawingml::ShapePtr pShape(new oox::drawingml::Shape("com.sun.star.drawing.CustomShape", /*bDefaultHeight=*/false));
        return new oox::drawingml::ShapeContext(*this, mpShape, pShape);
        // return new oox::shape::WpsContext(*this, uno::Reference<drawing::XShape>(),
        //                                   mpShape, pShape);
    }
    case XML_pic:
        return new oox::drawingml::GraphicShapeContext(*this, mpShape, std::make_shared<oox::drawingml::Shape>("com.sun.star.drawing.GraphicObjectShape"));
diff --git a/oox/source/shape/WpsContext.cxx b/oox/source/shape/WpsContext.cxx
index e196449..069c638 100644
--- a/oox/source/shape/WpsContext.cxx
+++ b/oox/source/shape/WpsContext.cxx
@@ -35,12 +35,11 @@
namespace shape
{

WpsContext::WpsContext(ContextHandler2Helper const& rParent, uno::Reference<drawing::XShape> xShape)
    : ContextHandler2(rParent),
WpsContext::WpsContext(ContextHandler2Helper const& rParent, uno::Reference<drawing::XShape> xShape, const drawingml::ShapePtr& pMasterShapePtr, const drawingml::ShapePtr& pShapePtr )
    : ShapeContext( rParent, pMasterShapePtr, pShapePtr ),
      mxShape(std::move(xShape))
{
    mpShape.reset(new oox::drawingml::Shape("com.sun.star.drawing.CustomShape"));
    mpShape->setWps(true);
    mpShapePtr->setWps(true);
}

WpsContext::~WpsContext() = default;
@@ -53,12 +52,6 @@
        break;
    case XML_cNvCnPr:
        break;
    case XML_cNvSpPr:
        break;
    case XML_spPr:
        return new oox::drawingml::ShapePropertiesContext(*this, *mpShape);
    case XML_style:
        return new oox::drawingml::ShapeStyleContext(*this, *mpShape);
    case XML_bodyPr:
        if (mxShape.is())
        {
@@ -189,8 +182,8 @@
        break;
    case XML_txbx:
    {
        mpShape->getCustomShapeProperties()->setShapeTypeOverride(true);
        mpShape->setTextBox(true);
        mpShapePtr->getCustomShapeProperties()->setShapeTypeOverride(true);
        mpShapePtr->setTextBox(true);
        //in case if the textbox is linked, save the attributes
        //for further processing.
        if (rAttribs.hasAttribute(XML_id))
@@ -200,18 +193,19 @@
            {
                oox::drawingml::LinkedTxbxAttr linkedTxtBoxAttr ;
                linkedTxtBoxAttr.id = id.get().toInt32();
                mpShape->setTxbxHasLinkedTxtBox(true);
                mpShape->setLinkedTxbxAttributes(linkedTxtBoxAttr);
                mpShapePtr->setTxbxHasLinkedTxtBox(true);
                mpShapePtr->setLinkedTxbxAttributes(linkedTxtBoxAttr);
            }
        }
        return this;
    }
    break;
    case XML_linkedTxbx:
    {
        //in case if the textbox is linked, save the attributes
        //for further processing.
        mpShape->getCustomShapeProperties()->setShapeTypeOverride(true);
        mpShape->setTextBox(true);
        mpShapePtr->getCustomShapeProperties()->setShapeTypeOverride(true);
        mpShapePtr->setTextBox(true);
        OptValue<OUString> id  = rAttribs.getString(XML_id);
        OptValue<OUString> seq = rAttribs.getString(XML_seq);
        if (id.has() && seq.has())
@@ -219,14 +213,13 @@
            oox::drawingml::LinkedTxbxAttr linkedTxtBoxAttr ;
            linkedTxtBoxAttr.id  = id.get().toInt32();
            linkedTxtBoxAttr.seq = seq.get().toInt32();
            mpShape->setTxbxHasLinkedTxtBox(true);
            mpShape->setLinkedTxbxAttributes(linkedTxtBoxAttr);
            mpShapePtr->setTxbxHasLinkedTxtBox(true);
            mpShapePtr->setLinkedTxbxAttributes(linkedTxtBoxAttr);
        }
    }
    break;
    default:
        SAL_WARN("oox", "WpsContext::createFastChildContext: unhandled element: " << getBaseToken(nElementToken));
        break;
        return ShapeContext::onCreateContext(nElementToken, rAttribs);
    }
    return nullptr;
}
diff --git a/oox/source/shape/WpsContext.hxx b/oox/source/shape/WpsContext.hxx
index e05a706..4571560 100644
--- a/oox/source/shape/WpsContext.hxx
+++ b/oox/source/shape/WpsContext.hxx
@@ -11,6 +11,7 @@
#define INCLUDED_OOX_SOURCE_SHAPE_WPSCONTEXT_HXX

#include <oox/core/contexthandler2.hxx>
#include <oox/drawingml/shapecontext.hxx>
#include <oox/drawingml/drawingmltypes.hxx>

namespace com
@@ -33,21 +34,18 @@
{

/// Wps is the drawingML equivalent of v:shape.
class WpsContext final : public oox::core::ContextHandler2
class WpsContext final : public oox::drawingml::ShapeContext
{
public:
    WpsContext(oox::core::ContextHandler2Helper const& rParent, css::uno::Reference<css::drawing::XShape> xShape);
    WpsContext(oox::core::ContextHandler2Helper const& rParent,
               css::uno::Reference<css::drawing::XShape> xShape,
               oox::drawingml::ShapePtr const & pMasterShapePtr,
               oox::drawingml::ShapePtr const & pShapePtr);
    ~WpsContext() override;

    oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElementToken, const oox::AttributeList& rAttribs) override;

    const oox::drawingml::ShapePtr& getShape() const
    {
        return mpShape;
    }

private:
    oox::drawingml::ShapePtr mpShape;
    css::uno::Reference<css::drawing::XShape> mxShape;
};

diff --git a/sd/qa/unit/data/xml/n819614_0.xml b/sd/qa/unit/data/xml/n819614_0.xml
index e51b520..8238da6 100644
--- a/sd/qa/unit/data/xml/n819614_0.xml
+++ b/sd/qa/unit/data/xml/n819614_0.xml
@@ -14,6 +14,14 @@
   <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
  </Transformation>
 </XShape>
 <XShape positionX="0" positionY="0" sizeX="100" sizeY="100" type="com.sun.star.drawing.GroupShape" name="Content Placeholder 4">
  <XShapes/>
  <Transformation>
   <Line1 column1="101.000000" column2="0.000000" column3="0.000000"/>
   <Line2 column1="0.000000" column2="101.000000" column3="0.000000"/>
   <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
  </Transformation>
 </XShape>
 <XShape positionX="182" positionY="2544" sizeX="25125" sizeY="16293" type="com.sun.star.drawing.GroupShape">
  <XShapes>
   <XShape positionX="10751" positionY="3496" sizeX="1563" sizeY="253" type="com.sun.star.drawing.CustomShape" fontHeight="18.000000" fontColor="ffffffff" textAutoGrowHeight="false" textAutoGrowWidth="false" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="BLOCK" textVerticalAdjust="TOP" textLeftDistance="250" textRightDistance="250" textUpperDistance="125" textLowerDistance="125" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="0" textMinimumFrameWidth="0" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="729fcf" fillTransparence="0" fillTransparenceGradientName="">
@@ -6824,12 +6832,4 @@
   <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
  </Transformation>
 </XShape>
 <XShape positionX="0" positionY="0" sizeX="100" sizeY="100" type="com.sun.star.drawing.GroupShape" name="Content Placeholder 4">
  <XShapes/>
  <Transformation>
   <Line1 column1="101.000000" column2="0.000000" column3="0.000000"/>
   <Line2 column1="0.000000" column2="101.000000" column3="0.000000"/>
   <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
  </Transformation>
 </XShape>
</XShapes>
diff --git a/sd/qa/unit/export-tests-ooxml1.cxx b/sd/qa/unit/export-tests-ooxml1.cxx
index 1a3a818..109c5a3 100644
--- a/sd/qa/unit/export-tests-ooxml1.cxx
+++ b/sd/qa/unit/export-tests-ooxml1.cxx
@@ -221,7 +221,7 @@

    // First smart art has blue font color (direct formatting)
    {
        const SdrObjGroup *pObjGroup = dynamic_cast<SdrObjGroup *>(pPage->GetObj(0));
        const SdrObjGroup *pObjGroup = dynamic_cast<SdrObjGroup *>(pPage->GetObj(1));
        CPPUNIT_ASSERT(pObjGroup);
        const SdrTextObj *pObj = dynamic_cast<SdrTextObj *>(pObjGroup->GetSubList()->GetObj(0));
        checkFontAttributes<Color, SvxColorItem>(pObj, Color(0x0000ff));
@@ -229,7 +229,7 @@

    // Second smart art has "dk2" font color (style)
    {
        const SdrObjGroup *pObjGroup = dynamic_cast<SdrObjGroup *>(pPage->GetObj(2)); // FIXME should be 1, smartart import creates an additional empty group for some reason
        const SdrObjGroup *pObjGroup = dynamic_cast<SdrObjGroup *>(pPage->GetObj(3)); // FIXME should be 1, smartart import creates an additional empty group for some reason
        CPPUNIT_ASSERT(pObjGroup);
        const SdrTextObj *pObj = dynamic_cast<SdrTextObj *>(pObjGroup->GetSubList()->GetObj(0));
        checkFontAttributes<Color, SvxColorItem>( pObj, Color(0x1F497D) );
@@ -237,7 +237,7 @@

    // Third smart art has white font color (style)
    {
        const SdrObjGroup *pObjGroup = dynamic_cast<SdrObjGroup *>(pPage->GetObj(4)); // FIXME should be 2, smartart import creates an additional empty group for some reason
        const SdrObjGroup *pObjGroup = dynamic_cast<SdrObjGroup *>(pPage->GetObj(5)); // FIXME should be 2, smartart import creates an additional empty group for some reason
        CPPUNIT_ASSERT(pObjGroup);
        const SdrTextObj *pObj = dynamic_cast<SdrTextObj *>(pObjGroup->GetSubList()->GetObj(0));
        checkFontAttributes<Color, SvxColorItem>(pObj, Color(0xffffff));
@@ -365,7 +365,7 @@

    // Check z-order of the two shapes, use background color to identify them
    // First object in the background has blue background color
    const SdrObjGroup *pObjGroup = dynamic_cast<SdrObjGroup *>(pPage->GetObj(0));
    const SdrObjGroup *pObjGroup = dynamic_cast<SdrObjGroup *>(pPage->GetObj(1));
    CPPUNIT_ASSERT(pObjGroup);
    const SdrObject *pObj = pObjGroup->GetSubList()->GetObj(0);
    CPPUNIT_ASSERT_MESSAGE( "no object", pObj != nullptr);
@@ -387,7 +387,7 @@
    const SdrPage *pPage = GetPage( 1, xDocShRef );

    // Same as testBnc870237, but here we check the horizontal spacing
    const SdrObjGroup *pObjGroup = dynamic_cast<SdrObjGroup *>(pPage->GetObj(0));
    const SdrObjGroup *pObjGroup = dynamic_cast<SdrObjGroup *>(pPage->GetObj(1));
    CPPUNIT_ASSERT(pObjGroup);
    const SdrObject* pObj = pObjGroup->GetSubList()->GetObj(1);
    CPPUNIT_ASSERT_MESSAGE( "no object", pObj != nullptr);
diff --git a/sd/qa/unit/export-tests-ooxml2.cxx b/sd/qa/unit/export-tests-ooxml2.cxx
index a472b0e..503b913 100644
--- a/sd/qa/unit/export-tests-ooxml2.cxx
+++ b/sd/qa/unit/export-tests-ooxml2.cxx
@@ -1410,10 +1410,10 @@
    xDocShRef->DoClose();

    xmlDocPtr pXmlDocContent = parseExport(tempFile, "ppt/slides/slide1.xml");
    assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:grpSp/p:sp[3]/p:spPr/a:xfrm/a:off", "x", "6796800");
    assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:grpSp/p:sp[3]/p:spPr/a:xfrm/a:off", "y", "4273920");
    assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:grpSp[1]/p:sp[1]/p:spPr/a:xfrm/a:off", "x", "4040640");
    assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:grpSp[1]/p:sp[1]/p:spPr/a:xfrm/a:off", "y", "4273920");
    assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:grpSp[2]/p:sp[1]/p:spPr/a:xfrm/a:off", "x", "4040640");
    assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:grpSp[2]/p:sp[1]/p:spPr/a:xfrm/a:off", "y", "4273920");
    assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:grpSp[2]/p:sp[3]/p:spPr/a:xfrm/a:off", "x", "6796800");
    assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:grpSp[2]/p:sp[3]/p:spPr/a:xfrm/a:off", "y", "4273920");
}

void SdOOXMLExportTest2::testGroupsRotatedPosition()
diff --git a/sd/qa/unit/import-tests.cxx b/sd/qa/unit/import-tests.cxx
index e8827df..0234733 100644
--- a/sd/qa/unit/import-tests.cxx
+++ b/sd/qa/unit/import-tests.cxx
@@ -435,7 +435,7 @@

    const SdrPage *pPage = GetPage( 1, xDocShRef );
    {
        SdrObjGroup *pGrpObj = dynamic_cast<SdrObjGroup *>( pPage->GetObj( 0 ) );
        SdrObjGroup *pGrpObj = dynamic_cast<SdrObjGroup *>( pPage->GetObj( 1 ) );
        CPPUNIT_ASSERT( pGrpObj );
        SdrObjCustomShape *pObj = dynamic_cast<SdrObjCustomShape *>( pGrpObj->GetSubList()->GetObj( 0 ) );
        CPPUNIT_ASSERT( pObj );
@@ -815,7 +815,7 @@
    const SdrPage *pPage = GetPage( 1, xDocShRef );

    // Simulate a:ext inside dsp:txXfrm with changing the lower distance
    const SdrObjGroup* pObj = dynamic_cast<SdrObjGroup*>( pPage->GetObj( 0 ) );
    const SdrObjGroup* pObj = dynamic_cast<SdrObjGroup*>( pPage->GetObj( 1 ) );
    CPPUNIT_ASSERT_MESSAGE( "no object", pObj != nullptr);
    CPPUNIT_ASSERT_EQUAL( sal_Int32(0), pObj->GetMergedItem(SDRATTR_TEXT_UPPERDIST).GetValue());
    CPPUNIT_ASSERT_EQUAL( sal_Int32(9919), pObj->GetMergedItem(SDRATTR_TEXT_LOWERDIST).GetValue());
@@ -1262,7 +1262,7 @@
    uno::Reference< drawing::XDrawPage > xPage( getPage( 0, xDocShRef ) );

    // Get the first text box from group shape
    uno::Reference< container::XIndexAccess > xShape( xPage->getByIndex(0), uno::UNO_QUERY );
    uno::Reference< container::XIndexAccess > xShape( xPage->getByIndex(1), uno::UNO_QUERY );
    uno::Reference< beans::XPropertySet > xPropSet( xShape->getByIndex(2), uno::UNO_QUERY );
    CPPUNIT_ASSERT_MESSAGE( "no textbox shape", xPropSet.is() );

diff --git a/sw/source/core/doc/textboxhelper.cxx b/sw/source/core/doc/textboxhelper.cxx
index 686485f..2eda791 100644
--- a/sw/source/core/doc/textboxhelper.cxx
+++ b/sw/source/core/doc/textboxhelper.cxx
@@ -292,7 +292,8 @@
{
    tools::Rectangle aRet;
    aRet.SetEmpty();
    auto pCustomShape = dynamic_cast<SdrObjCustomShape*>(pShape->FindRealSdrObject());
    auto pSdrShape = pShape->FindRealSdrObject();
    auto pCustomShape = dynamic_cast<SdrObjCustomShape*>(pSdrShape);
    if (pCustomShape)
    {
        // Need to temporarily release the lock acquired in
@@ -307,12 +308,17 @@
        if (nLocks)
            xLockable->setActionLocks(nLocks);
    }
    else if (pSdrShape)
    {
        // fallback - get *any* bound rect we can possibly get hold of
        aRet = pSdrShape->GetCurrentBoundRect();
    }

    if (!bAbsolute && pCustomShape)
    if (!bAbsolute && pSdrShape)
    {
        // Relative, so count the logic (reference) rectangle, see the EnhancedCustomShape2d ctor.
        Point aPoint(pCustomShape->GetSnapRect().Center());
        Size aSize(pCustomShape->GetLogicRect().GetSize());
        Point aPoint(pSdrShape->GetSnapRect().Center());
        Size aSize(pSdrShape->GetLogicRect().GetSize());
        aPoint.AdjustX(-(aSize.Width() / 2));
        aPoint.AdjustY(-(aSize.Height() / 2));
        tools::Rectangle aLogicRect(aPoint, aSize);
diff --git a/sw/source/core/unocore/unodraw.cxx b/sw/source/core/unocore/unodraw.cxx
index 1235469..9652f79 100644
--- a/sw/source/core/unocore/unodraw.cxx
+++ b/sw/source/core/unocore/unodraw.cxx
@@ -585,16 +585,16 @@
                sal::static_int_cast< sal_IntPtr >( xShapeTunnel->getSomething(SvxShape::getUnoTunnelId()) ));
    }

    if(!pShape || pShape->GetRegisteredIn() || !pShape->m_bDescriptor )
    {
        uno::RuntimeException aExcept;
        if(pShape)
            aExcept.Message = "object already inserted";
        else
            aExcept.Message = "illegal object";
        throw aExcept;
    }
    // this is not a writer shape
    if(!pShape)
        throw uno::RuntimeException("illegal object",
                                    static_cast< cppu::OWeakObject * > ( this ) );

    // we're already registered in the model / SwXDrawPage::add() already called
    if(pShape->GetRegisteredIn() || !pShape->m_bDescriptor )
        return;

    // we're inserted elsewhere already
    if ( pSvxShape->GetSdrObject() )
    {
        if ( pSvxShape->GetSdrObject()->IsInserted() )
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index 5affdd4..190f625 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -2946,6 +2946,8 @@

void DomainMapper::lcl_startShape(uno::Reference<drawing::XShape> const& xShape)
{
    assert(xShape.is());

    if (m_pImpl->GetTopContext())
    {
        // If there is a deferred page break, handle it now, so that the
diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx
index 1c3448f..0d50937 100644
--- a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx
+++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx
@@ -18,6 +18,7 @@
 */

#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/xml/sax/FastShapeContextHandler.hpp>
#include <com/sun/star/xml/sax/SAXException.hpp>
#include <ooxml/resourceids.hxx>
@@ -48,6 +49,7 @@
using namespace ::com::sun::star;
using namespace oox;
using namespace ::std;
using namespace ::com::sun::star::xml::sax;

/*
  class OOXMLFastContextHandler
@@ -1735,7 +1737,9 @@
                        mrShapeContext->createFastChildContext(Element, Attribs);

                    OOXMLFastContextHandlerWrapper * pWrapper =
                        new OOXMLFastContextHandlerWrapper(this, pChildContext);
                        new OOXMLFastContextHandlerWrapper(this,
                                                           pChildContext,
                                                           this);

                    if (!bGroupShape)
                    {
@@ -1744,7 +1748,6 @@
                        pWrapper->addNamespace(NMSP_vmlOffice);
                        pWrapper->addToken( NMSP_vml|XML_textbox );
                    }

                    xContextHandler.set(pWrapper);
                }
                else
@@ -1792,8 +1795,11 @@

OOXMLFastContextHandlerWrapper::OOXMLFastContextHandlerWrapper
(OOXMLFastContextHandler * pParent,
 uno::Reference<XFastContextHandler> const & xContext)
: OOXMLFastContextHandler(pParent), mxContext(xContext)
 uno::Reference<XFastContextHandler> const & xContext,
 rtl::Reference<OOXMLFastContextHandlerShape> const & xShapeHandler)
    : OOXMLFastContextHandler(pParent),
      mxWrappedContext(xContext),
      mxShapeHandler(xShapeHandler)
{
    setId(pParent->getId());
    setToken(pParent->getToken());
@@ -1809,16 +1815,16 @@
 const OUString & Name,
 const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
{
    if (mxContext.is())
        mxContext->startUnknownElement(Namespace, Name, Attribs);
    if (mxWrappedContext.is())
        mxWrappedContext->startUnknownElement(Namespace, Name, Attribs);
}

void SAL_CALL OOXMLFastContextHandlerWrapper::endUnknownElement
(const OUString & Namespace,
 const OUString & Name)
{
    if (mxContext.is())
        mxContext->endUnknownElement(Namespace, Name);
    if (mxWrappedContext.is())
        mxWrappedContext->endUnknownElement(Namespace, Name);
}

uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
@@ -1829,8 +1835,8 @@
{
    uno::Reference< xml::sax::XFastContextHandler > xResult;

    if (mxContext.is())
        xResult = mxContext->createUnknownChildContext
    if (mxWrappedContext.is())
        xResult = mxWrappedContext->createUnknownChildContext
            (Namespace, Name, Attribs);
    else
        xResult.set(this);
@@ -1841,7 +1847,7 @@
void OOXMLFastContextHandlerWrapper::attributes
(const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
{
    if (mxContext.is())
    if (mxWrappedContext.is())
    {
        OOXMLFastContextHandler * pHandler = getFastContextHandler();
        if (pHandler != nullptr)
@@ -1869,15 +1875,15 @@
(Token_t Element,
 const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
{
    if (mxContext.is())
        mxContext->startFastElement(Element, Attribs);
    if (mxWrappedContext.is())
        mxWrappedContext->startFastElement(Element, Attribs);
}

void OOXMLFastContextHandlerWrapper::lcl_endFastElement
(Token_t Element)
{
    if (mxContext.is())
        mxContext->endFastElement(Element);
    if (mxWrappedContext.is())
        mxWrappedContext->endFastElement(Element);
}

uno::Reference< xml::sax::XFastContextHandler >
@@ -1899,22 +1905,29 @@
    bool bSkipImages = getDocument()->IsSkipImages() && oox::getNamespace(Element) == NMSP_dml &&
        !((oox::getBaseToken(Element) == XML_linkedTxbx) || (oox::getBaseToken(Element) == XML_txbx));

    if ( bInNamespaces && ((!bIsWrap && !bIsSignatureLine) || dynamic_cast<OOXMLFastContextHandlerShape&>(*mpParent).isShapeSent()) )
    if ( bInNamespaces && ((!bIsWrap && !bIsSignatureLine)
                           || mxShapeHandler->isShapeSent()) )
    {
        xResult.set(OOXMLFactory::createFastChildContextFromStart(this, Element));
    else if (mxContext.is()  && !bSkipImages)
    }
    else if (mxWrappedContext.is()  && !bSkipImages)
    {
        OOXMLFastContextHandlerWrapper * pWrapper =
            new OOXMLFastContextHandlerWrapper
            (this, mxContext->createFastChildContext(Element, Attribs));
            (this, mxWrappedContext->createFastChildContext(Element, Attribs),
             mxShapeHandler);
        pWrapper->mMyNamespaces = mMyNamespaces;
        pWrapper->mMyTokens = mMyTokens;
        pWrapper->setPropertySet(getPropertySet());
        xResult.set(pWrapper);
    }
    else
    {
        xResult.set(this);
    }

    if ( bInTokens )
        static_cast<OOXMLFastContextHandlerShape*>(mpParent)->sendShape( Element );
        mxShapeHandler->sendShape( Element );

    return xResult;
}
@@ -1922,15 +1935,15 @@
void OOXMLFastContextHandlerWrapper::lcl_characters
(const OUString & aChars)
{
    if (mxContext.is())
        mxContext->characters(aChars);
    if (mxWrappedContext.is())
        mxWrappedContext->characters(aChars);
}

OOXMLFastContextHandler *
OOXMLFastContextHandlerWrapper::getFastContextHandler() const
{
    if (mxContext.is())
        return dynamic_cast<OOXMLFastContextHandler *>(mxContext.get());
    if (mxWrappedContext.is())
        return dynamic_cast<OOXMLFastContextHandler *>(mxWrappedContext.get());

    return nullptr;
}
@@ -1938,7 +1951,7 @@
void OOXMLFastContextHandlerWrapper::newProperty
(Id nId, const OOXMLValue::Pointer_t& pVal)
{
    if (mxContext.is())
    if (mxWrappedContext.is())
    {
        OOXMLFastContextHandler * pHandler = getFastContextHandler();
        if (pHandler != nullptr)
@@ -1949,7 +1962,7 @@
void OOXMLFastContextHandlerWrapper::setPropertySet
(const OOXMLPropertySet::Pointer_t& pPropertySet)
{
    if (mxContext.is())
    if (mxWrappedContext.is())
    {
        OOXMLFastContextHandler * pHandler = getFastContextHandler();
        if (pHandler != nullptr)
@@ -1964,7 +1977,7 @@
{
    OOXMLPropertySet::Pointer_t pResult(mpPropertySet);

    if (mxContext.is())
    if (mxWrappedContext.is())
    {
        OOXMLFastContextHandler * pHandler = getFastContextHandler();
        if (pHandler != nullptr)
@@ -1978,7 +1991,7 @@
{
    string sResult = "Wrapper(";

    if (mxContext.is())
    if (mxWrappedContext.is())
    {
        OOXMLFastContextHandler * pHandler = getFastContextHandler();
        if (pHandler != nullptr)
@@ -1994,7 +2007,7 @@
{
    OOXMLFastContextHandler::setId(rId);

    if (mxContext.is())
    if (mxWrappedContext.is())
    {
        OOXMLFastContextHandler * pHandler = getFastContextHandler();
        if (pHandler != nullptr)
@@ -2006,7 +2019,7 @@
{
    Id nResult = OOXMLFastContextHandler::getId();

    if (mxContext.is())
    if (mxWrappedContext.is())
    {
        OOXMLFastContextHandler * pHandler = getFastContextHandler();
        if (pHandler != nullptr && pHandler->getId() != 0)
@@ -2020,7 +2033,7 @@
{
    OOXMLFastContextHandler::setToken(nToken);

    if (mxContext.is())
    if (mxWrappedContext.is())
    {
        OOXMLFastContextHandler * pHandler = getFastContextHandler();
        if (pHandler != nullptr)
@@ -2032,7 +2045,7 @@
{
    Token_t nResult = OOXMLFastContextHandler::getToken();

    if (mxContext.is())
    if (mxWrappedContext.is())
    {
        OOXMLFastContextHandler * pHandler = getFastContextHandler();
        if (pHandler != nullptr)
diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx
index 29842cc..03aab00 100644
--- a/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx
+++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx
@@ -483,7 +483,9 @@
class OOXMLFastContextHandlerWrapper : public OOXMLFastContextHandler
{
public:
    explicit OOXMLFastContextHandlerWrapper(OOXMLFastContextHandler * pParent, css::uno::Reference<css::xml::sax::XFastContextHandler> const & xContext);
    OOXMLFastContextHandlerWrapper(OOXMLFastContextHandler * pParent,
                                   css::uno::Reference<css::xml::sax::XFastContextHandler> const & xContext,
            rtl::Reference<OOXMLFastContextHandlerShape> const & xShapeHandler);
    virtual ~OOXMLFastContextHandlerWrapper() override;

    // css::xml::sax::XFastContextHandler:
@@ -523,7 +525,8 @@
    virtual Token_t getToken() const override;

private:
    css::uno::Reference<css::xml::sax::XFastContextHandler> mxContext;
    css::uno::Reference<css::xml::sax::XFastContextHandler> mxWrappedContext;
    rtl::Reference<OOXMLFastContextHandlerShape> mxShapeHandler;
    std::set<Id> mMyNamespaces;
    std::set<Token_t> mMyTokens;
    OOXMLPropertySet::Pointer_t mpPropertySet;
diff --git a/writerfilter/source/rtftok/rtfsdrimport.cxx b/writerfilter/source/rtftok/rtfsdrimport.cxx
index 7960f12..ee3d24e 100644
--- a/writerfilter/source/rtftok/rtfsdrimport.cxx
+++ b/writerfilter/source/rtftok/rtfsdrimport.cxx
@@ -1082,10 +1082,13 @@
    }

    // Send it to dmapper
    m_rImport.Mapper().startShape(xShape);
    if (bClose)
    if (xShape.is())
    {
        m_rImport.Mapper().endShape();
        m_rImport.Mapper().startShape(xShape);
        if (bClose)
        {
            m_rImport.Mapper().endShape();
        }
    }
    m_xShape = xShape;
}